package top.im

import java.util.UUID
import java.util.concurrent.TimeUnit

import akka.actor.ActorRef
import akka.pattern.ask
import akka.util.Timeout
import io.undertow.Handlers._
import io.undertow.Undertow
import io.undertow.server.handlers.resource.ClassPathResourceManager
import io.undertow.server.{HttpHandler, HttpServerExchange}
import io.undertow.util.Headers
import io.undertow.websockets.WebSocketConnectionCallback
import io.undertow.websockets.core.WebSocketChannel
import io.undertow.websockets.spi.WebSocketHttpExchange
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._
import top.im.messages.{Here, NewConnect, Push, WhereIAm}

import scala.concurrent.Await
import scala.concurrent.duration.Duration

/**
  * Created by jf on 2016/11/15.
  */
object HttpServer {

  implicit val timeout = Timeout.apply(15, TimeUnit.SECONDS)

  def start(host: String, port: Int)(implicit pushServer: ActorRef) = {
    Undertow.builder().addHttpListener(port, host)
      .setHandler(path().addPrefixPath("/ws", websocket(new WebSocketConnectionCallback() {
        override def onConnect(exchange: WebSocketHttpExchange, channel: WebSocketChannel): Unit = {
          val params = exchange.getRequestParameters.get("pushId")
          val pushId = if (params == null || params.isEmpty) UUID.randomUUID().toString.replaceAll("-", "") else params.get(0)
          pushServer ! NewConnect(pushId, exchange, channel)
        }
      }))
        .addPrefixPath("/auth", path(new HttpHandler {
          override def handleRequest(exchange: HttpServerExchange): Unit = {
            exchange.getResponseHeaders.add(Headers.CONTENT_TYPE, "application/json;")

            // should auth with appId and appSecret and generate the pushId prefix with appId.
            val pushId = UUID.randomUUID().toString.replaceAll("-", "")

            var json = ("pushId" -> pushId) ~ ("timestamp" -> System.currentTimeMillis())
            val response = exchange.getResponseSender
            val where = pushServer ? WhereIAm(pushId)
            val address = Await.result(where, Duration.Inf)
            address match {
              case Here(address) => json = json ~ ("address" -> address)
            }

            println(json)
            response.send(compact(render(json)))
          }
        }))
        .addPrefixPath("/push", path(new HttpHandler {
          override def handleRequest(exchange: HttpServerExchange): Unit = {
            val params = exchange.getQueryParameters
            val msg = params.get("msg")
            val to = params.get("to")
            pushServer ! Push(to.getLast, msg.getLast)
            exchange.getResponseSender.close()
          }
        }))
        .addPrefixPath("/", resource(new ClassPathResourceManager(Boot.getClass.getClassLoader, "webapp")).addWelcomeFiles("index.html"))
      ).build().start()
  }

}
